<?php

	namespace org\tekuna\framework\request;
	
	use \InvalidArgumentException;
	
	
	class Url {
		
		protected
			$sLocalHost,
		
			$sProtocol,
			$sUser,
			$sPassword,
			$sHost,
			$iPort,
			$sPath,
			$arrParameters,
			$sFragment;
			
			
		public function __construct($sUrl = null, $sLocalHost = null) {
			
			$this -> resetUrl();
			
			if ($sUrl !== null) {
				
				$this -> setUrl($sUrl);
			}
			
			if ($sLocalHost === null) {
				
				$sLocalHost = $_SERVER['SERVER_NAME'];
			}
			
			$this -> sLocalHost = $sLocalHost;
		}
		
		protected function resetUrl() {
			
			$this -> sProtocol = 'http';
			$this -> sUser = '';
			$this -> sPassword = '';
			$this -> sHost = 'localhost';
			$this -> iPort = 80;
			$this -> sPath = '/';
			$this -> arrParameters = array();
			$this -> sFragment = '';
		}
		
		public function setUrl($sUrl) {
			
			$arrParsedUrl = parse_url($sUrl);
			
			$this -> resetUrl();
			
			if (isset($arrParsedUrl['scheme'])) {

				$this -> sProtocol = $arrParsedUrl['scheme'];
			}

			if (isset($arrParsedUrl['user'])) {

				$this -> sUser = $arrParsedUrl['user'];
			}

			if (isset($arrParsedUrl['pass'])) {

				$this -> sPassword = $arrParsedUrl['pass'];
			}

			if (isset($arrParsedUrl['host'])) {

				$this -> sHost = $arrParsedUrl['host'];
			}

			if (isset($arrParsedUrl['port'])) {

				$this -> iPort = (int) $arrParsedUrl['port'];
			}

			if (isset($arrParsedUrl['path'])) {

				$this -> sPath = $arrParsedUrl['path'];
			}

			if (isset($arrParsedUrl['query'])) {

				parse_str($arrParsedUrl['query'], $this -> arrParameters);
			}

			if (isset($arrParsedUrl['fragment'])) {

				$this -> sFragment = $arrParsedUrl['fragment'];
			}
		}
		
		public function __toString() {
			
			// render relative on local host
			if ($this -> sLocalHost == $this -> sHost) {
				
				return $this -> renderRelative();
			}
			else {
				
				return $this -> renderAbsolute();
			}
		}
		
		public function renderAbsolute() {
			
			$sUrl = "$this->sProtocol://";
			
			if ($this -> sUser != '') {
				
				$sUrl .= $this -> sUser;
				
				if ($this -> sPassword != '') {
					
					$sUrl .= ':'. $this -> sPassword;
				}
				
				$sUrl .= '@';
			}
			
			$sUrl .= $this -> sHost;
			
			if ($this -> iPort != 80) {
				
				$sUrl .= ':'. $this -> iPort;
			}
			
			$sUrl .= $this -> renderRelative();
			
			return $sUrl;
		}
		
		public function renderRelative() {
			
			$sUrl = $this -> sPath;
			
			if ($this -> arrParameters != array()) {
				
				$sUrl .= '?'. http_build_query($this -> arrParameters);
			}
			
			if ($this -> sFragment != '') {
				
				$sUrl .= '#'. $this -> sFragment;
			}
			
			return $sUrl;
		}
		
		public function setProtocol($sProtocol) {
		
			$this -> sProtocol = $sProtocol;
		}
		
		public function getProtocol() {
		
			return $this -> sProtocol;
		}
		
		public function setUser($sUser) {
		
			$this -> sUser = $sUser;
		}
		
		public function getUser() {
		
			return $this -> sUser;
		}
		
		public function setPassword($sPassword) {
		
			$this -> sPassword = $sPassword;
		}
		
		public function getPassword() {
		
			return $this -> sPassword;
		}
		
		public function setHost($sHost) {
		
			$this -> sHost = $sHost;
		}
		
		public function getHost() {
		
			return $this -> sHost;
		}
		
		public function setPort($iPort) {
		
			$this -> iPort = (int) $iPort;
		}
		
		public function getPort() {
		
			return $this -> iPort;
		}
		
		public function setPath($sPath) {
		
			$this -> sPath = $sPath;
		}
		
		public function getPath() {
		
			return $this -> sPath;
		}
		
		public function setParameters($arrParameters) {
		
			$this -> arrParameters = $arrParameters;
		}
		
		public function getParameters() {
		
			return $this -> arrParameters;
		}
		
		public function setParameter($sName, $sValue) {
		
			$this -> arrParameters[$sName] = $sValue;
		}
		
		public function getParameter($sName) {
		
			if (! isset($this -> arrParameters[$sName])) {
			
				throw new InvalidArgumentException("The parameter '$sName' is not set.");
			}
			
			return $this -> arrParameters[$sName];
		}
		
		public function removeParameters() {
			
			$this -> arrParameters = array();
		}
		
		public function setFragment($sFragment) {
		
			$this -> sFragment = $sFragment;
		}
		
		public function getFragment() {
		
			return $this -> sFragment;
		}
	}